// Package controller @author dingrui @since 2021/11/29
package controller

import (
	"fmt"
	"strconv"
	"time"

	"github.com/bannirui/mini-prize/common"
	"github.com/bannirui/mini-prize/config"
	"github.com/bannirui/mini-prize/dal/model"
	"github.com/bannirui/mini-prize/dal/service"
	"github.com/bannirui/mini-prize/dto"
	"github.com/bannirui/mini-prize/web/util"
)

type LuckyApi struct {
}

func (api *LuckyApi) luckyDo(uid int, username, ip string) (int, string, *dto.GiftDTO) {
	// 分布式锁竞争
	ok := util.LockLucky(uid)
	if ok {
		defer util.UnlockLucky(uid)
	} else {
		return 102, "正在抽奖，请稍后重试", nil
	}

	// 验证用户今日参与次数
	userDayNum := util.IncrUserLuckyNum(uid)
	if userDayNum > config.UserPrizeMax {
		return 103, "今日的抽奖次数已用完，明天再来吧", nil
	} else {
		ok = api.checkUserday(uid, userDayNum)
		if !ok {
			return 103, "今日的抽奖次数已用完，明天再来吧", nil
		}
	}

	// 验证IP今日的参与次数
	ipDayNum := util.IncrIpLuckyNum(ip)
	if ipDayNum > config.IpLimitMax {
		return 104, "相同IP参与次数太多，明天再来参与吧", nil
	}

	limitBlack := false // 黑名单
	if ipDayNum > config.IpPrizeMax {
		limitBlack = true
	}
	// 验证IP黑名单
	var blackipInfo *model.BlackIp
	if !limitBlack {
		ok, blackipInfo = api.checkBlackip(ip)
		if !ok {
			fmt.Println("黑名单中的IP", ip, limitBlack)
			limitBlack = true
		}
	}

	// 验证用户黑名单
	var userInfo *model.User
	if !limitBlack {
		ok, userInfo = api.checkBlackUser(uid)
		if !ok {
			limitBlack = true
		}
	}

	// 获得抽奖编码
	prizeCode := common.Random(10000)
	// 8 匹配奖品是否中奖
	prizeGift := api.prize(prizeCode, limitBlack)
	if prizeGift == nil ||
		prizeGift.PrizeNum < 0 ||
		(prizeGift.PrizeNum > 0 && prizeGift.LeftNum <= 0) {
		return 205, "很遗憾，没有中奖，请下次再试", nil
	}

	// 有限制奖品发放
	if prizeGift.PrizeNum > 0 {
		if util.GetGiftPoolNum(prizeGift.Id) <= 0 {
			return 206, "很遗憾，没有中奖，请下次再试", nil
		}
		ok = util.PrizeGift(prizeGift.Id, prizeGift.LeftNum)
		if !ok {
			return 207, "很遗憾，没有中奖，请下次再试", nil
		}
	}

	// 不同编码的优惠券的发放
	if prizeGift.Gtype == config.GtypeCodeDiff {
		code := util.PrizeCodeDiff(prizeGift.Id)
		if code == "" {
			return 208, "很遗憾，没有中奖，请下次再试", nil
		}
		prizeGift.Gdata = code
	}

	// 记录中奖记录
	result := model.Result{
		GiftId:     prizeGift.Id,
		GiftName:   prizeGift.Title,
		GiftType:   prizeGift.Gtype,
		Uid:        uid,
		Username:   username,
		PrizeCode:  prizeCode,
		GiftData:   prizeGift.Gdata,
		GmtCreated: common.NowUnix(),
		Ip:         ip,
		Status:     0,
	}
	err := service.G_resultService.Create(&result)
	if err != nil {
		// TODO: 2021/11/29
		return 209, "很遗憾，没有中奖，请下次再试", nil
	}
	if prizeGift.Gtype == config.GtypeGiftLarge {
		// 如果获得了实物大奖，需要将用户、IP设置成黑名单一段时间
		api.prizeLarge(ip, uid, username, userInfo, blackipInfo)
	}
	// 12 返回抽奖结果
	return 0, "", prizeGift
}

func (api *LuckyApi) checkUserday(uid int, num int64) bool {
	userDayInfo := service.G_userDayService.GetUserToday(uid)
	if userDayInfo != nil && userDayInfo.Uid == uid {
		// 今天存在抽奖记录
		if userDayInfo.Cnt >= config.UserPrizeMax {
			if int(num) < userDayInfo.Cnt {
				util.InitUserLuckyNum(uid, int64(userDayInfo.Cnt))
			}
			return false
		} else {
			userDayInfo.Cnt++
			if int(num) < userDayInfo.Cnt {
				util.InitUserLuckyNum(uid, int64(userDayInfo.Cnt))
			}
			err103 := service.G_userDayService.Update(userDayInfo, nil)
			if err103 != nil {
				// TODO: 2021/11/29
			}
		}
	} else {
		// 创建今天的用户参与记录
		y, m, d := time.Now().Date()
		strDay := fmt.Sprintf("%d%02d%02d", y, m, d)
		day, _ := strconv.Atoi(strDay)
		userDayInfo = &model.UserDay{
			Uid:        uid,
			Day:        day,
			Cnt:        1,
			GmtCreated: int(time.Now().Unix()),
		}
		err103 := service.G_userDayService.Create(userDayInfo)
		if err103 != nil {
			// TODO: 2021/11/29
		}
		util.InitUserLuckyNum(uid, 1)
	}
	return true
}

func (api *LuckyApi) checkBlackip(ip string) (bool, *model.BlackIp) {
	var (
		blackIp *model.BlackIp
	)
	blackIp = service.G_blackIpService.GetByIp(ip)
	if blackIp == nil || blackIp.Ip == "" {
		return true, nil
	}
	if blackIp.ExpireTime > int(time.Now().Unix()) {
		// IP黑名单存在，并且还在黑名单有效期内
		return false, blackIp
	}
	return true, blackIp
}

func (api *LuckyApi) checkBlackUser(uid int) (bool, *model.User) {
	info := service.G_userService.Get(uid)
	if info != nil && info.BlackExpireTime > int(time.Now().Unix()) {
		// 黑名单存在并且有效
		return false, info
	}
	return true, info
}

func (api *LuckyApi) prize(prizeCode int, limitBlack bool) *dto.GiftDTO {
	var (
		prizeGift *dto.GiftDTO
	)
	giftList := service.G_giftService.GetAllUse(true)
	for _, gift := range giftList {
		if gift.PrizeCodeA <= prizeCode &&
			gift.PrizeCodeB >= prizeCode {
			// 中奖编码区间满足条件，说明可以中奖
			if !limitBlack || gift.Gtype < config.GtypeGiftSmall {
				prizeGift = &gift
				break
			}
		}
	}
	return prizeGift
}

func (api *LuckyApi) prizeLarge(ip string,
	uid int, username string,
	userinfo *model.User,
	blackipInfo *model.BlackIp) {
	nowTime := common.NowUnix()
	blackTime := 30 * 86400
	// 更新用户的黑名单信息
	if userinfo == nil || userinfo.Id <= 0 {
		userinfo = &model.User{
			Id:              uid,
			Username:        username,
			BlackExpireTime: nowTime + blackTime,
			GmtCreated:      nowTime,
			Ip:              ip,
		}
		_ = service.G_userService.Create(userinfo)
	} else {
		userinfo = &model.User{
			Id:              uid,
			BlackExpireTime: nowTime + blackTime,
			GmtUpdated:      nowTime,
		}
		_ = service.G_userService.Update(userinfo, nil)
	}
	// 更新要IP的黑名单信息
	if blackipInfo == nil || blackipInfo.Id <= 0 {
		blackipInfo = &model.BlackIp{
			Ip:         ip,
			ExpireTime: nowTime + blackTime,
			GmtCreated: nowTime,
		}
		_ = service.G_blackIpService.Create(blackipInfo)
	} else {
		blackipInfo.ExpireTime = nowTime + blackTime
		blackipInfo.GmtUpdated = nowTime
		_ = service.G_blackIpService.Update(blackipInfo, nil)
	}
}
